package repository

import (
	"github.com/lab-online/internal/class/infra/model"
	"github.com/lab-online/internal/shared/code"
	"github.com/lab-online/pkg/database"
	"github.com/lab-online/pkg/util"

	"github.com/lab-online/internal/class/constant"
	"github.com/lab-online/internal/class/entity"
)

func (r *Repository) GetClassByID(id uint) (entity.ClassEntity, error) {
	if id == 0 {
		return nil, constant.DBErrClassNotFound
	}

	query := model.New(model.WithID(id))
	err := r.db.Where(query).First(query).Error

	if err != nil {
		return nil, errorHandler(err)
	}

	return query.ToEntity(), nil
}

// GetClasses 获取班级列表, 若指定学生则查询该学生所在班级包含学生信息, 否则仅查询班级信息
func (r *Repository) GetClasses(
	classEntity entity.ClassEntity,
) ([]entity.ClassEntity, error) {
	if classEntity.GetID() != 0 {
		if class, err := r.GetClassByID(classEntity.GetID()); err != nil {
			return []entity.ClassEntity{}, code.ErrorPicker(
				err, code.DatabaseClassNotFound, nil,
			)
		} else {
			return []entity.ClassEntity{class}, nil
		}
	}

	db := r.db
	if len(classEntity.GetStudentVOs()) != 0 {
		db = db.InnerJoins(
			"INNER JOIN students ON students.username = ? AND students.class_id = classes.id",
			classEntity.GetStudentVOs()[0].GetUsername(),
		)
	}
	if classEntity.GetName() != "" {
		db = db.Where("name LIKE ?", "%"+classEntity.GetName()+"%")
	}

	query := model.New(model.WithTeacher(classEntity.GetTeacher()))
	var classes []*model.Class
	if err := db.Where(query).Find(&classes).Error; err != nil {
		return nil, errorHandler(err)
	}

	return util.SliceMap(classes, func(class *model.Class) entity.ClassEntity {
		return class.ToEntity()
	}), nil
}

// GetClassWithStudentsByID 获取班级及学生
func (r *Repository) GetClassWithStudentsByID(
	id uint,
) (entity.ClassEntity, error) {
	if id == 0 {
		return nil, constant.DBErrClassNotFound
	}

	query := model.New(model.WithID(id))
	err := r.db.Preload("Students").Where(query).First(query).Error

	if err != nil {
		return nil, errorHandler(err)
	}

	return query.ToEntity(), nil
}

func (r *Repository) CheckClassIncludeStudent(class uint, student string) (bool, error) {
	if err := r.db.Take(&model.Student{
		ClassID:  class,
		Username: student,
	}).Error; err != nil {
		if database.IsRecordNotFound(err) {
			return false, nil
		}
		return false, constant.DBErrUnknown
	}

	return true, nil
}

func (r *Repository) GetClassIDsForStudent(username string) ([]uint, error) {
	var students []*model.Student
	if err := r.db.Where(&model.Student{}).Find(&students).Error; err != nil {
		return nil, errorHandler(err)
	}

	return util.SliceMap(students, func(student *model.Student) uint {
		return student.ClassID
	}), nil
}
